/*
 * Client.cpp
 *
 *  Created on: Nov 4, 2011
 *      Author: gonzalo
 */

#include "Client.h"
#include "../Translator/Translator.h"
#include "../../gui/WindowHelper.h"
#include "../Constantes.h"


Client::Client(std::string id,std::string host,SocketProtocoloPlano* socket,SDLEngine* engine){
	this->mensajesSDL= new ColaMensajesSDL();
	this->enviar = new ColaMensajeEnviar(id);
	this->recibir = new ColaMensajeRecibir(id);
	this->game = new BattleMasterPlayerGame(id);
	this->conexion = new ConexionCliente(id,host,game,socket,enviar,recibir);
	this->jugadores = new UsersTanks(id,engine);
	this->id = id;

	//Levanto la parte SDL
	this->engine = engine;
	this->engine->initPlayPanel(game);
	this->engine->addExternalNotify(mensajesSDL);

	clientNotifier = new ClientNotifier(recibir,mensajesSDL);

	this->conexionActiva = true;
}

Client::~Client() {
	//No borrar el engine, es de la aplicacion, no del cliente
	delete enviar;
	delete recibir;
	delete conexion;
	delete game;
}

void Client::setMensaje(DTO* dto){
	this->enviar->setMensaje(dto);
}

void* Client::run(){
	void* leido;
	TypeNotifier tipoLeido;

	clientNotifier->start();

	while(conexionActiva){

		leido = clientNotifier->pull(&tipoLeido);
		if(!leido)
			continue;

		switch (tipoLeido) {
			case CLIENT_NOTIFY_DTO:{
				//Tomo los mensajes de la cola de mensajes
				DTO* dto = (DTO*)leido;

				handleMensaje(dto);
			}break;
			case CLIENT_NOTIFY_EVENT:{
				//Replico los eventos locales al servidor
				Event* event = (Event*)leido;
				//Si no tiene sender es un evento de teclado,sino es remoto
				if(event->getSender().empty()){
					event->setSender(this->id);
					this->enviar->setMensaje(Translator::translate(event));
				}
			}break;
		}
	}

	return NULL;
}

void Client::terminar(){
	conexionActiva =false;

	recibir->terminar();
	mensajesSDL->terminar();
	enviar->terminar();
	clientNotifier->terminar();

	enviar->signal();
	recibir->signal();
	mensajesSDL->signal();
	clientNotifier->signal();

	conexion->terminar();
}

void Client::handleMensaje(DTO *dto){
	//EVENT, BACKGROUND, ELEMENT, CLIENTE, FIN_HANDSHAKE

	//En esta instancia solo puedo tener event y client, nada mas,
	//si hay mas lo desecho e informo, porque seria un error
	switch (dto->getType()) {
		case CLIENTE:{
				DTOCliente* dtoClient = ((DTOCliente*)dto);
				jugadores->handleUserMessage(dtoClient);
				//Mando mi estado al resto si alguien se conecto, que no sea yo mismo
				if ( (dtoClient->getStatus() == INFORM)
						|| (dtoClient->getStatus() == CONNECTED && dtoClient->getClientId() != this->id) )
					this->setMensaje(getTankDTO());

				//TODO implement
				//Se cae el server, salir del juego
				if(dtoClient->getStatus() == SERVER_SHUTDOWN){
					conexionActiva=false;
					engine->setNewEvent(Translator::translate(dtoClient));
				}


			}break;
		default:
				//TODO verificar que no este generando trafico de mas.
				//Lo paso al translate para que opere.
				engine->setNewEvent(Translator::translate((DTOEvent*)dto));
			break;
	}
}


DTO* Client::getTankDTO(){
	return this->jugadores->getLocalTankDTO(this->id);
}
